package redis.inaction.xx.interceptor;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Base64Utils;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import redis.inaction.xx.cache.SessionRedisCache;
import redis.inaction.xx.utils.*;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import static redis.inaction.xx.utils.ResponseCode.DENY;

@Slf4j
public class UserAndLogInterceptor implements HandlerInterceptor {

    private static final String USER_ID_PARAM_NAME = "uid";
    private static final String C_CODE_PARAM_NAME = "c_code";
    private static final String ACCESS_RAN_KEY_PARAM_NAME = "access_key";

    @Autowired
    private UserClient userClient;

    @Autowired
    private SessionRedisCache sessionRedisCache;

    @Autowired
    private XXClientPropertyConfig clientPropertyConfig;


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        setResponseHeader(request,response);
        preHandleRequestCompare(request);
        String requestPath = request.getRequestURI();
        if(isIgnore(requestPath)){
            log.info("非白名单URL:{}", requestPath);
            return true;
        }
        if(isUserIgnore(requestPath)){
            log.info("白名单URL:{},无需验证Uid", requestPath);
            return true;
        }

        String uid = request.getParameter(USER_ID_PARAM_NAME);
        String cCode = request.getParameter(C_CODE_PARAM_NAME);
        String randomAccessKey = request.getParameter(ACCESS_RAN_KEY_PARAM_NAME);

        try{
            String realUserId = isTinyAppRequest(request) ? getUserIdForTinyApp(request, response) : getRealUid(uid);
            if( realUserId == null ){
                log.warn("empty realUserId error.");
                return false;
            }
            ThreadLocalContext.setLoginUserId(realUserId);
        }catch (Exception e){
            return false;
        }

        ThreadLocalContext.setCode(cCode);
        if(randomAccessKey == null){
            log.warn("No randomAccessKey params");
        } else {
            ThreadLocalContext.setAccessKey(randomAccessKey);
        }

        return true;
    }


    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        ThreadLocalContext.cleanContext();
    }

    private String getUserIdForTinyApp(HttpServletRequest request, HttpServletResponse response){
        String authCode = request.getParameter("auth_code");
        //兼容安卓客户端session在账户切换时无法清空问题
        if(!StringUtils.hasText(authCode)){
            String userId = sessionRedisCache.getSessionUserId(request);
            if(StringUtils.hasText(userId)){
                log.debug("return userId from session cache.");
                return userId;
            }
        }

        if (!StringUtils.hasText(authCode)) {
            log.warn("No userId and authCode, will deny by front side");
            writeErrorResponse(response, "No auth_code error");
            return null;
        }
        String aliUid = userClient.fetchUserId(authCode);
        if(!StringUtils.hasText(aliUid)){
            log.warn("Both userId and authCode empty, will deny by front side");
            writeErrorResponse(response, "empty aliUid error");
            return null;
        }
        sessionRedisCache.setSessionUserId(request, response, aliUid);
        return aliUid;
    }

    private String getRealUid(String encodedUid){
        if(!StringUtils.hasText(encodedUid)){
            return null;
        }
        MonitorLogger.debug("uid: {0}", encodedUid);
        byte[] uidBase64 = Base64Utils.decodeFromString(encodedUid);
        byte[] byteUid = RSAUtil.decryptByPrivateKey(uidBase64, clientPropertyConfig.getUserDecodePrivateKey());
        return new String(byteUid);
    }

    private boolean isIgnore(String requestPath){
        return false;
    }

    private boolean isUserIgnore(String requestPath){
        return false;
    }

    private void setResponseHeader(HttpServletRequest request, HttpServletResponse response){
        Cookie cookie = new Cookie("SESSION", request.getSession().getId());
        response.addCookie(cookie);
    }

    private void writeErrorResponse(HttpServletResponse response, String msg){
        try{
            SendMsgUtil.sendJsonMessage(response, CommonResponse.createFail(DENY, msg));
        }catch (Exception e){
            MonitorLogger.error("Fail to write error msg to font", e);
        }
    }

    private void preHandleRequestCompare(HttpServletRequest request){
        //灰度流量设置
    }

    private boolean isTinyAppRequest(HttpServletRequest request){
        //小程序请求demo
        log.debug("return true for tiny app demo");
        return true;
    }
}
